package progetto1.csm.implementation;

import progetto1.csm.core.SystemElement;
import progetto1.csm.core.actor.Client;
import progetto1.csm.core.actor.Element;
import progetto1.csm.core.actor.Watcher;
import sde.actor.Message;
import sde.actor.distribution.Distribution;

public class Source extends Element{
	
	private static class Init extends Message{
		private Distribution distribution;
		private Element nextElement;
		private int nClient;
		
		private Init(int nClient, Distribution distribution, Element nextElement) {
			this.distribution = distribution;
			this.nextElement = nextElement;
			this.nClient = nClient;
		}
	}
	
	private static class Ready extends Message{
		private Arrival a;//cosi' gli arrival vengono creati una volta sola

		private Ready(Arrival a) {
			this.a = a;
		}
	}

	private final byte CREATED = 0, OPERATING = 1;
	private int ccis = 0;//current client in system
	private int nClient;
	private Distribution distribution;
	private Element nextElement;
	

	protected Source( Watcher watcher, SystemElement element) {
		super(watcher, element);
	}

	protected int getNClient(){
		return nClient;
	}
	
	protected void init(int nClient, Distribution distibution, Element nextElement){
		send(new Init(nClient, distibution, nextElement));
		ccis = 0;
		Client.resetIDS();
		become(CREATED);
	}
	
	private double getNextSample(){
		return now()+distribution.nextSample();
	}
	
	@Override
	public void handler(Message m) {
		switch (currentStatus()) {
		case CREATED:
			if(m instanceof Init){
				Init i = (Init)m;
				this.distribution = i.distribution;
				this.nextElement = i.nextElement;
				this.nClient = i.nClient;
				for (int j = 0; j < nClient; j++) {
					send(new Arrival(new Client()));
				}
				become(OPERATING);
			}
			break;
		case OPERATING:
			if(m instanceof Arrival){
				Arrival a = (Arrival) m;
				if(ccis > 0){
					exit(a.getClient());//un cliente è uscito dal sistema
					ccis--;
					if(ccis == 0){
						idle();
					}
				}
				send(new Ready(a),getNextSample());
			}
			else if(m instanceof Ready){
				Ready r = (Ready) m;
				enter(r.a.getClient());//entra nel sistema un nuovo job
				ccis++;
				nextElement.send(r.a);
			}
			break;
		default:
			assert false;
			break;
		}
		
	}

}
